//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   QuadratureFactory.cc
 * \author Jeremy Roberts
 * \date   06/21/2011
 * \brief  QuadratureFactory member definitions.
 * \note   Copyright (C) 2011 Jeremy Roberts.  Adapted from Denovo.
 */
//---------------------------------------------------------------------------//
// $Rev:: 141                                           $:Rev of last commit
// $Author:: j.alyn.roberts@gmail.com                   $:Author of last commit
// $Date:: 2011-09-14 19:28:23 +0000 (Wed, 14 Sep 2011) $:Date of last commit
//---------------------------------------------------------------------------//

#include "angle/QuadratureFactory.hh"
#include "../utilities/SP.hh"
#include "../utilities/DBC.hh"
#include "../utilities/Constants.hh"

// Quadratures.
#include "angle/Level_Symmetric_3D.hh"
#include "angle/Uniform_Equal_3D.hh"
#include "angle/Quadruple_Range_2D.hh"
#include "angle/Gauss_Legendre_1D.hh"

namespace slabtran
{

//---------------------------------------------------------------------------//
// CONSTRUCTOR
//---------------------------------------------------------------------------//
/*!
 * \brief Constructor.
 */
template <class D>
QuadratureFactory<D>::QuadratureFactory()
{
}

//---------------------------------------------------------------------------//
// PUBLIC INTERFACE
//---------------------------------------------------------------------------//
/*!
 * \brief build constructs a Quadrature object.
 *
 * The Quadrature creator only requires 1 parameter -- the quadrature
 * identifier (see QuadratureFactory::QID).  The two addtional parameters can
 * optionally be used to specify the sn_order and a normalization for the
 * quadrature weights.  The sn_order defaults to 4 and the default value for
 * normalization constant varies with the dimensionality of the quadrature set
 * (2, \f$ 2\pi\f$ or \f$ 4\pi\f$ for 1D, 2D or 3D sets).
 *
 * Another parameter may need to be added to this constructor to specify
 * the number of dimensions requested.  Currently QID directly specifies
 * the dimensionality of the quadrature set.
 *
 * \param quad_type An identifier that specifies the type of quadrature to
 * construct.
 *
 * \param sn_order The SN order for the constructed quadrature set. (Default:
 * 4)
 *
 * \param norm The sum of the quadrature weights are forced to sum to this
 * value. (Default: 2, \f$ 2\pi\f$ or \f$ 4\pi\f$ based on the dimensionality
 * of the quadrature set.)

 * \return Smart pointer to a Quadrature object.
 */
template <class D>
typename QuadratureFactory<D>::SP_Quadrature QuadratureFactory<D>::build(int quad_type,
                                                                         int sn_order,
                                                                         double norm)
{
  SP_Quadrature quad;

  // switch on quad_type, note that most of these are not yet implemented
  switch (quad_type)
  {
  case LEVELSYM:
  {
    // 2D/3D Level-symmetric quadrature
    // default normalization of 4*pi
    Insist(D::dimension == 2 || D::dimension == 3,
        "Level-symmetric quadrature is only available for"
        " 2-d and 3-d problems.");
    if (norm == 0.0) norm = four_pi;
    if (D::dimension == 3) quad = new Level_Symmetric_3D(sn_order, norm);
    else
      quad = new Level_Symmetric_2D(sn_order, norm);
    break;
  }
  case UNIEQUAL:
  {
    // 2D/3D Uniform equal weight quadrature
    // default normalization of 4*pi
    Insist(D::dimension == 2 || D::dimension == 3,
            "Uniform equal weight quadrature is only available for"
            " 2-d and 3-d problems.");
    if (norm == 0.0) norm = four_pi;
    if (D::dimension == 3) quad = new Uniform_Equal_3D(sn_order, norm);
    else
      quad = new Uniform_Equal_2D(sn_order, norm);
    break;
  }
  case QUADRUPLE:
  {
    // 2D Symmetric Quadruple Range
    // default normalization of 4*pi
    Insist(D::dimension == 2,
        "Symmetric quadruple range quadrature is only available for"
        " 2-d problems.");
    if (norm == 0.0) norm = four_pi;
    quad = new Quadruple_Range_2D(sn_order, norm);
    break;
  }
  case GAUSSLEG:
  {
    // 1D Gauss-Legendre
    // specify a default of 2.0
    Insist(D::dimension == 1,
        "Gauss-Legendre quadrature is available only for 1-d problems.");
    if (norm == 0.0) norm = 2.0;
    quad = new Gauss_Legendre_1D(sn_order, norm);
    break;
  }
  default:
  {
    throw util::assertion("Unknown or unimplemented value for quad_type.");
    break;
  }
  }

  Ensure (quad);
  return quad;
}

// instantiations
template class QuadratureFactory<Dimension<1> > ;
template class QuadratureFactory<Dimension<2> > ;
template class QuadratureFactory<Dimension<3> > ;

} // end namespace slabtran

//---------------------------------------------------------------------------//
//                 end of QuadratureFactory.cc
//---------------------------------------------------------------------------//
